﻿using System;
using System.Linq;
using Stimulus360.Models.Data;
using System.Collections.Generic;
using Stimulus360.Models.Data.CustomTypes;
using Stimulus360.Repositories.Interfaces;

namespace Stimulus360.Tests.Repositories
{
    /// <summary>
    ///     Class represents an implementation of IDataRepository to test CRUD operations on the 
    ///     Idea and Project entities
    /// </summary>
    /// <remarks>
    ///     Not all methods have been implemented currently. Only  methods accessed by the test cases
    ///     have been implemented
    /// </remarks>
    class FakeDataRepository : IDataRepository
    {
        #region IDataRepository Members

        /// <summary>
        ///     An in- memory  list of Ideas to be used
        /// </summary>
        private List<Idea> _ideaList;

        /// <summary>
        ///     An in- memory list of projects to be used
        /// </summary>
        private List<Project> _projectList;

        /// <summary>
        ///     Constructor. Sets the idea and project lists to be use
        /// </summary>
        /// <param name="ideaList">
        ///     Idea list to be used
        /// </param>
        /// <param name="projectsList">
        ///     Project list to be used
        /// </param>
        public FakeDataRepository(List<Idea> ideaList, List<Project> projectsList)
        {
            _ideaList = ideaList;
            _projectList = projectsList;
        }


        #region Implemented Methods

        /// <summary>
        ///     Method to retrive list of projects related to the given project
        /// </summary>
        /// <param name="projectId">
        ///     The Project for which related projects are to be retrieved
        /// </param>
        /// <returns>
        ///     List of projects related to the given project
        /// </returns>
        public ICollection<Project> GetRelatedProjects(int projectId)
        {
            Project project = FindProjectById(projectId);
            return (from relatedProject in FindProjectsInCategory(project.InvestmentCategory.Category)
                    where relatedProject.Status != (byte)ProjectStatus.Cancelled && relatedProject.ProjectId != projectId
                    orderby relatedProject.DateCreated descending
                    select relatedProject).Take(10).ToList();
        }

        /// <summary>
        ///     Method to get all projects in a given category in descending order of date submitted.
        /// </summary>
        /// <param name="category">
        ///     Category title of the Category
        /// </param>
        /// <returns>
        ///     All projects in the given category in descending order of date submitted.
        /// </returns>
        public IQueryable<Project> FindProjectsInCategory(string category)
        {
            return (from project in _projectList
                    where project.InvestmentCategory.Category == category
                    orderby project.DateCreated descending
                    select project).AsQueryable();
        }


        /// <summary>
        ///     Method to return the project for the given project ID
        /// </summary>
        /// <param name="projectId">
        ///     The project ID for which project has to be returned.
        /// </param>
        /// <returns>
        ///     Project for the given project ID
        /// </returns>
        public Project FindProjectById(int projectId)
        {
            return _projectList.SingleOrDefault(project => project.ProjectId == projectId);
        }

        /// <summary>
        ///     Method to get all the ideas in the system in descending order of date submitted.
        /// </summary>
        /// <returns>
        ///     All Ideas in descending order of date submitted
        /// </returns>
        public IQueryable<Idea> GetAllIdeas()
        {
            return (from idea in _ideaList
                    orderby idea.DateSubmitted descending
                    select idea).AsQueryable();
        }

        /// <summary>
        ///     Method to get the top N ideas ordered by Average rating
        /// </summary>
        /// <param name="topN">
        ///     Number of ideas to be returned
        /// </param>
        /// <returns>
        ///     Top "N" ideas ordered by Average rating
        /// </returns>
        public IQueryable<Idea> GetTopNIdeas(int topN)
        {
            return ((from idea in _ideaList
                     orderby idea.AverageRating descending
                     select idea).Take(topN)).AsQueryable();
        }

        /// <summary>
        ///     Method to get all ideas of the given status ordered by date submitted
        /// </summary>
        /// <param name="status">
        ///     The Status to be considered
        /// </param>
        /// <returns>
        ///    All ideas of the given status ordered by date submitted
        /// </returns>
        public IQueryable<Idea> FindIdeasByStatus(IdeaStatus status)
        {
            return (from idea in _ideaList
                    where idea.Status == (byte)status
                    orderby idea.DateSubmitted descending
                    select idea).AsQueryable();
        }

        /// <summary>
        ///     Method to save a new Idea
        /// </summary>
        /// <param name="idea">
        ///     Idea to be created.
        /// </param>
        public void CreateIdea(Idea idea)
        {
            _ideaList.Add(idea);
        }

        /// <summary>
        ///     Method to return the Idea for the given idea ID
        /// </summary>
        /// <param name="ideaId">
        ///     The Idea ID for which Idea has to be returned.
        /// </param>
        /// <returns>
        ///     Idea for the given idea ID
        /// </returns>
        public Idea FindIdeaById(int ideaId)
        {
            return _ideaList.SingleOrDefault(idea => idea.IdeaId == ideaId);

        }
        /// <summary>
        ///     Method to updated an edited idea to the database
        /// </summary>
        public void UpdateIdea()
        {
            foreach (Idea idea in _ideaList)
            {
                if (!idea.IsValid)
                {
                    throw new ApplicationException("Rule Voilations");
                }
            }
        }

        /// <summary>
        ///     Method to retrieve list of ideas satisfying the search criteria
        /// </summary>
        /// <param name="searchText">
        ///     The search criteria
        /// </param>
        /// <returns>
        ///     The list of ideas satisfying the search criteria
        /// </returns>
        public IQueryable<Idea> FindIdeasBySearchString(string searchText)
        {
            return (from idea in _ideaList
                    where
                        (idea.Title.ToLower().Contains(searchText.ToLower()) == true) ||
                        (idea.InvestmentCategory.Category.ToLower() == searchText.ToLower())
                    orderby idea.DateSubmitted descending
                    select idea).AsQueryable();
        }

        /// <summary>
        ///     Method to get the list of ideas submitted by the given user
        /// </summary>
        /// <param name="userName">
        ///     User whose submitted idea list is to be retrieved
        /// </param>
        /// <returns>
        ///     List of ideas submitted by the given user.
        /// </returns>
        public IQueryable<Idea> GetSubmittedIdeas(string userName)
        {
            return (from idea in _ideaList
                    where idea.SubmittedBy == userName
                    orderby idea.DateSubmitted descending
                    select idea).AsQueryable();
        }

        /// <summary>
        ///     Method to return a summary of all the Investment Categories
        /// </summary>
        /// <returns>
        ///     Summary of all the Investment Categories
        /// </returns>
        public ICollection<InvestmentCategorySummary> GetAllInvestmentCategorySummaries()
        {
            return null;
        }

        #endregion

        #region Not Implemented Region
        //Functionalities accessing these methods have not been shown in these test cases.
        //Hence these methods have not been implemented for this Fake Repository

        public IQueryable<Project> GetNewProjects()
        {
            throw new NotImplementedException();
        }

        public IQueryable<Project> FindProjectsBySearchString(string searchText)
        {
            throw new NotImplementedException();
        }

        public IQueryable<Project> GetTopNProjects(int topN)
        {
            throw new NotImplementedException();
        }

        public IQueryable<Project> FindProjectsByVolunteerStatus(bool required)
        {
            throw new NotImplementedException();
        }

        public IQueryable<Project> FindProjectsByStatus(ProjectStatus status)
        {
            throw new NotImplementedException();
        }



        public IQueryable<ProjectRating> GetProjectFeedback(int projectId)
        {
            throw new NotImplementedException();
        }

        public ProjectRating GetProjectFeedback(int projectId, string userName)
        {
            throw new NotImplementedException();
        }

        public IQueryable<Volunteer> GetProjectVolunteers(int projectId)
        {
            throw new NotImplementedException();
        }

        public void UpdateProject()
        {
            throw new NotImplementedException();
        }

        public IQueryable<Project> GetFavoriteProjects(string userName)
        {
            throw new NotImplementedException();
        }

        public IQueryable<Project> GetRecommendedProjects(string userName)
        {
            throw new NotImplementedException();
        }

        public IQueryable<Project> GetVolunteeredProjects(string userName)
        {
            throw new NotImplementedException();

        }

        public void CreateProject(Project project)
        {
            throw new NotImplementedException();
        }



        public IQueryable<Idea> GetNewIdeas()
        {
            throw new NotImplementedException();
        }

        public IQueryable<Idea> FindIdeasInCategory(string category)
        {
            throw new NotImplementedException();
        }


        public IQueryable<IdeaRating> GetIdeaFeedback(int ideaId)
        {
            throw new NotImplementedException();
        }

        public IdeaRating GetIdeaFeedback(int ideaId, string userName)
        {
            throw new NotImplementedException();
        }

        public ICollection<ProjectSummary> GetProjectsForIdea(int ideaId)
        {
            throw new NotImplementedException();
        }

        public ICollection<Idea> GetRelatedIdeas(int ideaId)
        {
            throw new NotImplementedException();
        }

        public IQueryable<Idea> GetFavoriteIdeas(string userName)
        {
            throw new NotImplementedException();
        }

        public IQueryable<Idea> GetRecommendedIdeas(string userName)
        {
            throw new NotImplementedException();
        }

        #endregion

        #endregion
    }
}
